/*
	This file is part of Sandbox.

	Copyright (C) 2008  Marleine Daoud <marleine@gmail.com>

	Sandbox is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	Sandbox is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License 
	along with Sandbox.  If not, see <http://www.gnu.org/licenses/>.
*/

#import "search-algo.h" 
#import "graph.h"
#import <stdlib.h>
#import <list.h>

@implementation Predicate

+ (Predicate *) createPredicates: (GList *) predicates {
	GList *temp = g_list_last(predicates);
	//printf ("Temp Length: %d\n", g_list_length(temp));
	if(g_list_previous(temp)!=NULL)
	{
		//printf ("length > 1\n");
		gboolean donewithand = FALSE;
		int index;
		while(!donewithand)
		{
			//printf ("inside and\n");
			donewithand = TRUE;
			//printf("List Length %d\n", g_list_length(temp));
			temp = g_list_last(temp);
			//printf("List Length %d\n", g_list_length(temp));
			//Predicate *previous = temp->data;
			while(g_list_previous(temp))
			{
				Predicate *current = temp->data;
				Predicate *previous = g_list_previous(temp)->data;
				if(previous->ptype == CRITERIA && 
					((SearchItem *) previous)->andOrNull == AND)
				{
					//printf ("Creating AND Predicate\n");
					donewithand = FALSE;
					Predicate* ptemp = [[Predicate alloc] init];
					ptemp->p1 = previous;
					ptemp->p2 = current;
					ptemp->ptype = ANDP;
					index = g_list_index(temp, current);
					temp = g_list_insert(temp, ptemp, index);
					temp = g_list_first(temp);
					temp = g_list_remove(temp, current);
					temp = g_list_remove(temp, previous);
					//printf("List Length %d\n", g_list_length(temp));
					break;
				}
				//printf("List Length %d\n", g_list_length(temp));
				temp = g_list_previous(temp);
				//printf("List Length %d\n", g_list_length(temp));
			}
		}
		
		while(TRUE)
		{
			temp = g_list_first(temp);
			//printf("List Length %d\n", g_list_length(temp));
			temp = g_list_last(temp);
			//printf("Continuing Loop, temp= %d\n",temp);
			if(g_list_previous(temp))
			{
				//printf ("Constructing OR predicate\n");
				Predicate *current = temp->data;
				Predicate* previous = g_list_previous(temp)->data;
				Predicate* ptemp = [[Predicate alloc] init];
				ptemp->p1 = previous;
				ptemp->p2 = current;
				ptemp->ptype = ORP;
				//index = g_list_index(temp, current);
				temp = g_list_append(temp, ptemp);
				temp = g_list_first(temp);
				temp = g_list_remove(temp, current);
				temp = g_list_remove(temp, previous);
				
			}
			else break;
		}
	}
	return (Predicate *)(temp->data);
	
}

- (gboolean) evaluate: (Node *) node {
	//printf("type %d\n", self->ptype);
	if(self->ptype == CRITERIA)
	{
		//printf("Evaluate Criteria\n");
		if((((SearchItem *) self)->searchtype == SHAPETYPE) && 
			[node type] == ((SearchByTypeData *) self)->shapetype)
			return TRUE;
		else if((((SearchItem *) self)->searchtype == BORDERSTYLE) && 
			[node lineStyle] == 
				((SearchByBorderStyleData *) self)->borderstyle)
			return TRUE;
		else if((((SearchItem *) self)->searchtype == LINECOLOR) && 
			([node lineColor].R == 
				((SearchByLineColorData *) self)->linecolor.R) 
			&& ([node lineColor].G == 
				((SearchByLineColorData *) self)->linecolor.G) 
			&& ([node lineColor].B == 
				((SearchByLineColorData *) self)->linecolor.B) 
			&& ([node lineColor].A == 
				((SearchByLineColorData *) self)->linecolor.A))
			return TRUE;
		else if((((SearchItem *) self)->searchtype == FILLCOLOR) && 
			([node fillColor].R == 
				((SearchByFillColorData *) self)->fillcolor.R) 
			&& ([node fillColor].G == 
				((SearchByFillColorData *) self)->fillcolor.G) 
			&& ([node fillColor].B == 
				((SearchByFillColorData *) self)->fillcolor.B) 
			&& ([node fillColor].A == 
				((SearchByFillColorData *) self)->fillcolor.A))
			return TRUE;
		else if((((SearchItem *) self)->searchtype == COMMENT) && 
			(g_strcmp0([node comment], 
				((SearchByNoteData *) self)->comment) == 0))
			return TRUE;
		else return FALSE;
	}
	else if (self->ptype == ANDP)
	{
		//printf("Evaluate And\n");
		return [p1 evaluate: node] & [p2 evaluate: node];
	}
	else 
	{
		//printf("Evaluate Or\n");
		return [p1 evaluate: node] | [p2 evaluate: node];
	}
}

@end

@implementation SearchAlgo

- init {
	searchlist = [[List alloc] init];
	searchhistorylist = [[List alloc] init];
}

- free {
	[searchlist free];
	[searchhistorylist free];
}

char* intToString(int val)
{       
        if(val==0) return "0";
        int i=-1, x;
        if(val<0)
        {   
                x=-val;
                i++;
        }   
        else
                x=val;
        while(x>0)
        {   
                x/=10;
                i++;
        }   
        char * ret = malloc ((i+2)*sizeof(char));
		ret[i+1]='\0';
        x=val;
        if(val<0)
        {   
                ret[0] = '-';
                x=-x;
        }   
        while(x>0)
        {   
                ret[i] = 48 + (x%10) ;
                x/=10;
                i--;
        }   
        return ret;
}

+ search: (List *) nodeList: (int) type: (int) style: (float) linecolorR: 
	(float) linecolorG: (float) linecolorB: (float) linecolorA: 
	(float) fillcolorR: (float) fillcolorG: (float) fillcolorB: 
	(float) fillcolorA: (char *) note {
	
	int i = 0;
	while (i < [nodeList size]) {
		if ([[nodeList getItem: i] type] == type && 
			[[nodeList getItem: i] lineStyle] == style && 
			[[nodeList getItem: i] lineColor].R == linecolorR &&
			[[nodeList getItem: i] lineColor].G == linecolorG &&
			[[nodeList getItem: i] lineColor].B == linecolorB &&
			[[nodeList getItem: i] lineColor].A == linecolorA &&
			[[nodeList getItem: i] fillColor].R == fillcolorR &&
			[[nodeList getItem: i] fillColor].G == fillcolorG &&
			[[nodeList getItem: i] fillColor].B == fillcolorB &&
			[[nodeList getItem: i] fillColor].A == fillcolorA &&
			(g_strcmp0([[nodeList getItem: i] comment], note) == 0))
		   [[nodeList getItem : i] select];
		i++;
	}
}

+ (const char*) createHistoryUI: (GList *) historyList {
	GList *temph = g_list_last(historyList);
	char *criteriaString = malloc(sizeof (char) * 100);
	strcpy(criteriaString, "");
	GList *tempc = temph->data;
	printf("If crashed, then because label of search history too big\n");
	while(g_list_length(tempc)>=1)
	{
		if(((SearchItem *) tempc->data)->searchtype == SHAPETYPE)
		{
			strcat(criteriaString, "Type: ");
			if (((SearchByTypeData *) tempc->data)->shapetype == 0)
			{
				strcat(criteriaString, "Rectangle; \n");
			}
			else if (((SearchByTypeData *) tempc->data)->shapetype == 1)
			{
				strcat(criteriaString, "Ellipse; \n");
			}
			else if (((SearchByTypeData *) tempc->data)->shapetype == 2)
			{
				strcat(criteriaString, "Triangle; \n");
			}
			else if (((SearchByTypeData *) tempc->data)->shapetype == 3)
			{
				strcat(criteriaString, "Note; \n");
			}
		}
		else if(((SearchItem *) tempc->data)->searchtype == BORDERSTYLE)
		{
			strcat(criteriaString, "Border Style: ");
			if (((SearchByBorderStyleData *) tempc->data)->borderstyle == 0)
			{
				strcat(criteriaString, "Continuous; \n");
			}
			else if (((SearchByBorderStyleData *) tempc->data)->borderstyle == 1)
			{
				strcat(criteriaString, "Dashed; \n");
			}
		}
		else if(((SearchItem *) tempc->data)->searchtype == LINECOLOR)
		{
			strcat(criteriaString, "Line Border Color: ");
			//strcat(criteriaString, itoa((int)((SearchByLineColorData *) tempc->data)->linecolor.R)*255);
			strcat(criteriaString, intToString((int)(((SearchByLineColorData *) tempc->data)->linecolor.R*255)));
			strcat(criteriaString, ", ");
			strcat(criteriaString, intToString((int)(((SearchByLineColorData *) tempc->data)->linecolor.G*255)));
			strcat(criteriaString, ", ");
			strcat(criteriaString, intToString((int)(((SearchByLineColorData *) tempc->data)->linecolor.B*255)));
			strcat(criteriaString, ", ");
			strcat(criteriaString, intToString((int)(((SearchByLineColorData *) tempc->data)->linecolor.A*255)));
			strcat(criteriaString, "; \n");
		}
		else if(((SearchItem *) tempc->data)->searchtype == FILLCOLOR)
		{
			strcat(criteriaString, "Fill Color: ");
			//printf("drew %s\n", intToString(123));
			//printf("%d\n", (int)(((SearchByFillColorData *) tempc->data)->fillcolor.R*255));
			//printf("%d, %s\n", (((SearchByFillColorData *) tempc->data)->fillcolor.R)*255, intToString((((SearchByFillColorData *) tempc->data)->fillcolor.R)*255));
			strcat(criteriaString, intToString((int)(((SearchByFillColorData *) tempc->data)->fillcolor.R*255)));
			strcat(criteriaString, ", ");
			strcat(criteriaString, intToString((int)(((SearchByFillColorData *) tempc->data)->fillcolor.G*255)));
			strcat(criteriaString, ", ");
			strcat(criteriaString, intToString((int)(((SearchByFillColorData *) tempc->data)->fillcolor.B*255)));
			strcat(criteriaString, ", ");
			strcat(criteriaString, intToString((int)(((SearchByFillColorData *) tempc->data)->fillcolor.A*255)));
			strcat(criteriaString, "; \n");
		}
		else if(((SearchItem *) tempc->data)->searchtype == COMMENT)
		{
			strcat(criteriaString, "Comment: ");
			strcat(criteriaString, ((SearchByNoteData *) tempc->data)->comment);
			strcat(criteriaString, "; \n");
		}
		//printf("text: %s\n", criteriaString);
		tempc = g_list_next(tempc);
	}
	
	const char *criteriaDone = criteriaString;
	return criteriaDone;
}

@end

@implementation SearchItem
@end

@implementation SearchByTypeData
@end

@implementation SearchByBorderStyleData
@end

@implementation SearchByFillColorData
@end

@implementation SearchByLineColorData
@end

@implementation SearchByNoteData
@end

